/*
 * Unidata Platform Community Edition
 * Copyright (c) 2013-2020, UNIDATA LLC, All rights reserved.
 * This file is part of the Unidata Platform Community Edition software.
 *
 * Unidata Platform Community Edition is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Unidata Platform Community Edition is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
 */
package org.unidata.mdm.dq.core.type.model.source;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.unidata.mdm.core.type.model.ModelSource;
import org.unidata.mdm.core.type.model.source.AbstractModelSource;
import org.unidata.mdm.dq.core.configuration.DataQualityModelIds;
import org.unidata.mdm.dq.core.type.model.source.assignment.NameSpaceAssignmentSource;
import org.unidata.mdm.dq.core.type.model.source.rule.MappingSetSource;
import org.unidata.mdm.dq.core.type.model.source.rule.QualityRuleSource;
import org.unidata.mdm.dq.core.util.DQUtils;

import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;

/**
 * @author Mikhail Mikhailov on Jan 20, 2021
 */
@JacksonXmlRootElement(localName = "data-quality", namespace = DataQualityModel.NAMESPACE)
public class DataQualityModel extends AbstractModelSource<DataQualityModel> implements ModelSource, Serializable {
    /**
     * GSVUID.
     */
    private static final long serialVersionUID = 3887336547467686899L;
    /**
     * The NS.
     */
    public static final String NAMESPACE = "http://data-quality.mdm.unidata.org/";

    @JacksonXmlElementWrapper(useWrapping = false)
    @JacksonXmlProperty(localName = "javaFunction")
    private List<JavaCleanseFunctionSource> javaFunctions;

    @JacksonXmlElementWrapper(useWrapping = false)
    @JacksonXmlProperty(localName = "compositeFunction")
    private List<CompositeCleanseFunctionSource> compositeFunctions;

    @JacksonXmlElementWrapper(useWrapping = false)
    @JacksonXmlProperty(localName = "groovyFunction")
    private List<GroovyCleanseFunctionSource> groovyFunctions;

    @JacksonXmlElementWrapper(useWrapping = false)
    @JacksonXmlProperty(localName = "pythonFunction")
    private List<PythonCleanseFunctionSource> pythonFunctions;

    @JacksonXmlProperty(localName = "group")
    private CleanseFunctionGroup functionGroup;

    @JacksonXmlElementWrapper(useWrapping = false)
    @JacksonXmlProperty(localName = "rule")
    private List<QualityRuleSource> rules;

    @JacksonXmlElementWrapper(useWrapping = false)
    @JacksonXmlProperty(localName = "set")
    private List<MappingSetSource> sets;

    @JacksonXmlElementWrapper(useWrapping = false)
    @JacksonXmlProperty(localName = "assignments")
    private List<NameSpaceAssignmentSource> assignments;

    /**
     * Constructor.
     */
    public DataQualityModel() {
        super();
    }
    /**
     * {@inheritDoc}
     */
    @JacksonXmlProperty(isAttribute = true, localName = "instanceId")
    @Override
    public String getInstanceId() {
        // Singleton per storage id
        return DQUtils.DEFAULT_MODEL_INSTANCE_ID;
    }
    /**
     * {@inheritDoc}
     */
    @JacksonXmlProperty(isAttribute = true, localName = "typeId")
    @Override
    public String getTypeId() {
        return DataQualityModelIds.DATA_QUALITY;
    }
    /**
     * @return the functions
     */
    public List<JavaCleanseFunctionSource> getJavaFunctions() {
        if (javaFunctions == null) {
            javaFunctions = new ArrayList<>();
        }
        return javaFunctions;
    }
    /**
     * @param functions the functions to set
     */
    public void setJavaFunctions(List<JavaCleanseFunctionSource> functions) {
        this.javaFunctions = functions;
    }
    /**
     * @return the compositeFunctions
     */
    public List<CompositeCleanseFunctionSource> getCompositeFunctions() {
        if (compositeFunctions == null) {
            compositeFunctions = new ArrayList<>();
        }
        return compositeFunctions;
    }
    /**
     * @param compositeFunctions the compositeFunctions to set
     */
    public void setCompositeFunctions(List<CompositeCleanseFunctionSource> compositeFunctions) {
        this.compositeFunctions = compositeFunctions;
    }
    /**
     * @return the groovyFunctions
     */
    public List<GroovyCleanseFunctionSource> getGroovyFunctions() {
        if (groovyFunctions == null) {
            groovyFunctions = new ArrayList<>();
        }
        return groovyFunctions;
    }
    /**
     * @param groovyFunctions the groovyFunctions to set
     */
    public void setGroovyFunctions(List<GroovyCleanseFunctionSource> groovyFunctions) {
        this.groovyFunctions = groovyFunctions;
    }
    /**
     * @return the pythonFunctions
     */
    public List<PythonCleanseFunctionSource> getPythonFunctions() {
        if (pythonFunctions == null) {
            pythonFunctions = new ArrayList<>();
        }
        return pythonFunctions;
    }
    /**
     * @param pythonFunctions the pythonFunctions to set
     */
    public void setPythonFunctions(List<PythonCleanseFunctionSource> pythonFunctions) {
        this.pythonFunctions = pythonFunctions;
    }
    /**
     * @return the functionGroups
     */
    public CleanseFunctionGroup getFunctionGroup() {
        return functionGroup;
    }
    /**
     * @param functionGroups the functionGroups to set
     */
    public void setFunctionGroup(CleanseFunctionGroup functionGroup) {
        this.functionGroup = functionGroup;
    }
    /**
     * @return the rules
     */
    public List<QualityRuleSource> getRules() {
        if (rules == null) {
            rules = new ArrayList<>();
        }
        return rules;
    }
    /**
     * @param rules the rules to set
     */
    public void setRules(List<QualityRuleSource> rules) {
        this.rules = rules;
    }
    /**
     * @return the sets
     */
    public List<MappingSetSource> getSets() {
        if (sets == null) {
            sets = new ArrayList<>();
        }
        return sets;
    }
    /**
     * @param sets the sets to set
     */
    public void setSets(List<MappingSetSource> sets) {
        this.sets = sets;
    }
    /**
     * @return the assignments
     */
    public List<NameSpaceAssignmentSource> getAssignments() {
        if (assignments == null) {
            assignments = new ArrayList<>();
        }
        return assignments;
    }
    /**
     * @param assignments the assignments to set
     */
    public void setAssignments(List<NameSpaceAssignmentSource> assignments) {
        this.assignments = assignments;
    }

    public DataQualityModel withJavaFunctions(JavaCleanseFunctionSource... values) {
        if (ArrayUtils.isNotEmpty(values)) {
            return withJavaFunctions(Arrays.asList(values));
        }
        return this;
    }

    public DataQualityModel withJavaFunctions(Collection<JavaCleanseFunctionSource> values) {
        if (CollectionUtils.isNotEmpty(values)) {
            getJavaFunctions().addAll(values);
        }
        return this;
    }

    public DataQualityModel withCompositeFunctions(CompositeCleanseFunctionSource... values) {
        if (ArrayUtils.isNotEmpty(values)) {
            return withCompositeFunctions(Arrays.asList(values));
        }
        return this;
    }

    public DataQualityModel withCompositeFunctions(Collection<CompositeCleanseFunctionSource> values) {
        if (CollectionUtils.isNotEmpty(values)) {
            getCompositeFunctions().addAll(values);
        }
        return this;
    }

    public DataQualityModel withGroovyFunctions(GroovyCleanseFunctionSource... values) {
        if (ArrayUtils.isNotEmpty(values)) {
            return withGroovyFunctions(Arrays.asList(values));
        }
        return this;
    }

    public DataQualityModel withGroovyFunctions(Collection<GroovyCleanseFunctionSource> values) {
        if (CollectionUtils.isNotEmpty(values)) {
            getGroovyFunctions().addAll(values);
        }
        return this;
    }

    public DataQualityModel withPythonFunctions(PythonCleanseFunctionSource... values) {
        if (ArrayUtils.isNotEmpty(values)) {
            return withPythonFunctions(Arrays.asList(values));
        }
        return this;
    }

    public DataQualityModel withPythonFunctions(Collection<PythonCleanseFunctionSource> values) {
        if (CollectionUtils.isNotEmpty(values)) {
            getPythonFunctions().addAll(values);
        }
        return this;
    }

    public DataQualityModel withFunctionGroup(CleanseFunctionGroup functionGroup) {
        setFunctionGroup(functionGroup);
        return this;
    }

    public DataQualityModel withRules(QualityRuleSource... values) {
        if (ArrayUtils.isNotEmpty(values)) {
            return withRules(Arrays.asList(values));
        }
        return this;
    }

    public DataQualityModel withRules(Collection<QualityRuleSource> values) {
        if (CollectionUtils.isNotEmpty(values)) {
            getRules().addAll(values);
        }
        return this;
    }

    public DataQualityModel withSets(MappingSetSource... values) {
        if (ArrayUtils.isNotEmpty(values)) {
            return withSets(Arrays.asList(values));
        }
        return this;
    }

    public DataQualityModel withSets(Collection<MappingSetSource> values) {
        if (CollectionUtils.isNotEmpty(values)) {
            getSets().addAll(values);
        }
        return this;
    }

    public DataQualityModel withAssignments(NameSpaceAssignmentSource... values) {
        if (ArrayUtils.isNotEmpty(values)) {
            return withAssignments(Arrays.asList(values));
        }
        return this;
    }

    public DataQualityModel withAssignments(Collection<NameSpaceAssignmentSource> values) {
        if (CollectionUtils.isNotEmpty(values)) {
            getAssignments().addAll(values);
        }
        return this;
    }
}
